package com.xlhl.init.aop;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.EasyExcel;
import com.xlhl.init.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Optional;

/**
 * 处理 {@link com.xlhl.init.anno.ExportExcel} 注解的切面
 * <p>
 * 使用 <a href='https://easyexcel.opensource.alibaba.com/'>EasyExcel</a> 进行导出为 Excel
 * </p>
 *
 * @author xlhl
 */
@Aspect
@Component
@Slf4j
public class ExportExcelAspect {

    /**
     * 后置切面，将返回值全部转换为 Excel 并在浏览器下载
     * <p>
     * 返回值要求详见 {@link com.xlhl.init.anno.ExportExcel} 有说明
     * </p>
     *
     * @param result
     */
    @AfterReturning(pointcut = "@annotation(com.xlhl.init.anno.ExportExcel)", returning = "result")
    public void exportExcel(Result<?> result) {
        Object listData = result.getData();
        if (!(listData instanceof List<?> data)) {
            log.info("试图将返回写入 Excel，但他好像不是一个列表类型");
            return;
        }
        if (CollUtil.isEmpty(data)) {
            log.info("试图将返回写入 Excel，但它是一个空列表");
            return;
        }

        String fileName = Optional.ofNullable(result.getErrorMessage()).orElse(String.valueOf(System.currentTimeMillis()));

        log.info("正在将列表写入 Excel; 文件名称为: {}", fileName);

        HttpServletResponse response = ((ServletRequestAttributes)
                RequestContextHolder.currentRequestAttributes()).getResponse();
        if (response == null) {
            return;
        }
        response.reset();
        log.info("org.springframework.http.converter.HttpMessageNotWritableException 会报错说：");
        log.error("No converter for [class com.xlhl.init.common.Result] with preset Content-Type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'");
        log.info("但似乎对结果并没有什么影响，介意的可以自己想办法解决");
        log.info("如果导出的 Excel 有时间类型，导出 Excel 单元格 显示都是 ######。单元格设置小了，你把单元格拉长来");
        try (ServletOutputStream outputStream = response.getOutputStream()) {

            // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系

            response.setHeader("Content-disposition", "attachment;filename*=" + fileName + ".xlsx");
            EasyExcel.write(outputStream, data.get(0).getClass()).sheet(fileName).doWrite(data);
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}
